package xj.graph2d.graph;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

public class AbstractGraphComponent 
  implements GraphComponent, GraphConstants {

  public AbstractGraphComponent(int type) {
    this(type, null, null);
  }

  public AbstractGraphComponent(int type, String name) {
    this(type, null, name);
  }

  public AbstractGraphComponent(int type, Subgraph subg) {
    this(type, subg, null);
  }

  public AbstractGraphComponent(int type, Subgraph subg, String name) {
    this.name = name;
    attributes = new HashMap<String, Object>();
    if (subg != null) {
      setSubgraph(subg);
      setGraph(subg.getGraph());
    }
    setId();
  }

  public int getType() {
    return -1;
  }

  public boolean isNode() {
    return false;
  }

  public boolean isEdge() {
    return false;
  }

  public boolean isSubgraph() {
    return false;
  }

  public Graph getGraph() {
    return graph;
  }

  public Subgraph getSubgraph() {
    return subgraph;
  }

  public void setGraph(Graph graph) {
    this.graph = graph;
  }

  public void setSubgraph(Subgraph subgraph) {
    this.subgraph = subgraph;
  }

  public void addToSubgraph(Subgraph subgraph) {
    if (this.subgraph != subgraph) {
      switch (this.getType()) {
      case NODE:
	if (this.subgraph != null) {
	  this.subgraph.removeNode((GraphNode) this);
	}
	if (subgraph != null) {
	  subgraph.addNode((GraphNode) this);
	}
	break;
      case EDGE:
	if (this.subgraph != null) {
	  this.subgraph.removeEdge((GraphEdge) this);
	}
	if (subgraph != null) {
	  subgraph.addEdge((GraphEdge) this);
	}
	break;
      case SUBGRAPH:
	if (this.subgraph != null) {
	  this.subgraph.removeSubgraph((Subgraph) this);
	}
	if (subgraph != null) {
	  subgraph.addSubgraph((Subgraph) this);
	}
	break;
      }
    }
    this.subgraph = subgraph;
  }

  public void setAttribute(String name, Object value) {
    if (name != null && attributes != null) {
      if (value != null) {
	attributes.put(name, value);
      } else { 
	attributes.remove(name); 
      }
    }
  }

  public void removeAttribute(String name) {
    if (name != null && attributes != null) {
      attributes.remove(name);
    }
  }

  public Object getAttribute(String key) {
    if (key != null && attributes != null) {
      return attributes.get(key);
    }
    return null;
  }

  public boolean hasAttribute(String key) {
    if (key != null && attributes != null) {
      return attributes.containsKey(key);
    }
    return false;
  }

  public String getLabel() {
    return label;
  }

  public void setLabel(String label) {
    this.label = label;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public double getWeight() {
    return weight;
  }

  public void setWeight(double weight) {
    this.weight = weight;
  }

  public void setMark(int mark, boolean flag) {
    if (mark >= 0 && mark < 32) {
      int mask = (0x1 << mark);
      if (flag) {
	flags |= mask;
      } else {
	flags &= (~mask);
      }
    }
  }

  public boolean getMark(int mark) {
    if (mark >= 0 && mark < 32) {
      int mask = (0x1 << mark);
      return (flags & mask) != 0;
    }
    return false;
  }

  public void setAux(Object aux) {
    this.aux = aux;
  }

  public Object getAux() {
    return aux;
  }

  @Override
  public String toString() {
    if (canonName == null) {
      canonName = GraphUtilities.canonString(name);
    }
    return (canonName);
  }

  public void printElement(PrintWriter out) {
    String indent = new String(getGraph().getIndent());
    out.print(indent + toString());
    //getGraph().incrementIndent();
    //getGraph().decrementIndent();
    out.println();
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  protected void setId() {
    name = id = (getDefaultNamePrefix() + getNextId());
  }

  protected String getDefaultNamePrefix() {
    if (prefix != null) {
      return prefix + "c";
    } else {
      return "c";
    }
  }

  public static void setPrefix(String pre) {
    prefix = pre;
  }

  protected static String prefix = null;

  protected static int _id = 1;

  protected int getNextId() {
    return _id++;
  }

  protected String id;

  // the containing graph and the parent subgraph element
  protected Graph graph = null;

  protected Subgraph subgraph = null;

  // attributes
  protected Map<String, Object> attributes = null;

  // the name of the element
  protected String name;

  // canonical name
  protected String canonName = null;

  // the label of the element
  protected String label;

  protected double weight;

  protected int flags;

  protected Object aux;

}
